const axios = require('axios');
const cheerio = require('cheerio');
const fs = require('fs');
const path = require('path');

class MovieScraper {
    constructor() {
        this.defaultHeaders = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
            "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
            "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
            "priority": "u=0, i",
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": "\"Windows\"",
            "sec-fetch-dest": "document",
            "sec-fetch-mode": "navigate",
            "sec-fetch-site": "same-origin",
            "sec-fetch-user": "?1",
            "upgrade-insecure-requests": "1"
        };
    }

    async downloadPoster(posterUrl, filePath, retries = 3) {
        for (let attempt = 1; attempt <= retries; attempt++) {
            try {
                console.log(`正在下载海报 (尝试 ${attempt}/${retries}): ${posterUrl}`);

                const response = await axios.get(posterUrl, {
                    responseType: 'stream',
                    timeout: 30000, // 30秒超时
                    maxRedirects: 5, // 允许重定向
                    headers: {
                        ...this.defaultHeaders,
                        'Referer': 'https://www.themoviedb.org/'
                    }
                });

                const writer = fs.createWriteStream(filePath);
                response.data.pipe(writer);

                return new Promise((resolve, reject) => {
                    writer.on('finish', () => {
                        console.log(`海报已保存到: ${filePath}`);
                        resolve();
                    });
                    writer.on('error', (error) => {
                        fs.unlink(filePath, () => {}); // 删除不完整的文件
                        reject(error);
                    });
                });
            } catch (error) {
                console.error(`下载海报失败 (尝试 ${attempt}/${retries}):`, error.message);

                if (attempt === retries) {
                    console.error('所有下载尝试都失败了，跳过海报下载');
                    return; // 不抛出错误，继续执行程序
                }

                // 等待2秒后重试
                await new Promise(resolve => setTimeout(resolve, 2000));
            }
        }
    }

    async fetchMovieData(movieUrl) {
        console.log(`正在爬取电影信息: ${movieUrl}`);

        // 获取网页内容
        const response = await axios.get(movieUrl, {
            headers: this.defaultHeaders
        });

        const $ = cheerio.load(response.data);

        // 提取电影信息
        const movieInfo = this.extractMovieInfo($, movieUrl);

        // 生成XML文件
        const xmlContent = this.generateXML(movieInfo);

        return { movieInfo, xmlContent };
    }

    async scrapeMovieInfo(movieUrl) {
        try {
            const { movieInfo, xmlContent } = await this.fetchMovieData(movieUrl);

            // 保存XML文件
            const safeTitle = movieInfo.title.replace(/[^\u4e00-\u9fa5\w\s-]/g, '').replace(/\s+/g, '_') || 'movie';
            const fileName = `${safeTitle}.nfo`;
            fs.writeFileSync(fileName, xmlContent, 'utf8');

            console.log(`电影信息已保存到: ${fileName}`);

            // 下载第一张海报图片
            if (movieInfo.posters && movieInfo.posters.length > 0) {
                const firstPoster = movieInfo.posters[0];
                const posterExtension = 'jpg'; // 默认使用jpg格式
                const posterFileName = `${safeTitle}.${posterExtension}`;

                // 使用从网页提取的海报URL
                const posterUrl = firstPoster.full;

                console.log(`\n海报信息:`);
                console.log(`- 文件名: ${posterFileName}`);
                console.log(`- 下载链接: ${posterUrl}`);
                console.log(`- 手动下载命令: curl -L -o "${posterFileName}" "${posterUrl}"`);

                try {
                    await this.downloadPoster(posterUrl, posterFileName);
                } catch (error) {
                    console.log('\n自动下载失败，请使用上面的命令手动下载海报');
                }
            } else {
                console.log('未找到海报图片');
            }

            return movieInfo;

        } catch (error) {
            console.error('爬取电影信息时出错:', error.message);
            throw error;
        }
    }

    async scrapeMovieInfoToFolder(movieUrl, targetFolder, movieName) {
        try {
            const { movieInfo, xmlContent } = await this.fetchMovieData(movieUrl);

            // 保存XML文件到指定文件夹
            const nfoFileName = `${movieName}.nfo`;
            const nfoFilePath = path.join(targetFolder, nfoFileName);
            fs.writeFileSync(nfoFilePath, xmlContent, 'utf8');

            console.log(`电影信息已保存到: ${nfoFilePath}`);

            // 下载第一张海报图片到指定文件夹
            if (movieInfo.posters && movieInfo.posters.length > 0) {
                const firstPoster = movieInfo.posters[0];
                const posterExtension = 'jpg'; // 默认使用jpg格式
                const posterFileName = `${movieName}.${posterExtension}`;
                const posterFilePath = path.join(targetFolder, posterFileName);

                // 使用从网页提取的海报URL
                const posterUrl = firstPoster.full;

                console.log(`下载海报到: ${posterFilePath}`);

                try {
                    await this.downloadPoster(posterUrl, posterFilePath);
                } catch (error) {
                    console.log(`海报下载失败: ${error.message}`);
                }
            } else {
                console.log('未找到海报图片');
            }

            return movieInfo;

        } catch (error) {
            console.error('爬取电影信息时出错:', error.message);
            throw error;
        }
    }

    extractMovieInfo($, movieUrl) {
        const movieInfo = {};

        // 获取页面文本内容，避免重复声明
        const bodyText = $('body').text();

        // 提取标题 - 从页面标题中提取
        const pageTitle = $('title').text();
        const titleMatch = pageTitle.match(/^(.+?)\s*\(\d{4}\)/);
        if (titleMatch) {
            movieInfo.title = titleMatch[1].trim();
        } else {
            movieInfo.title = $('h1').first().text().trim() || '未知电影';
        }

        // 从页面内容中提取原始标题
        const originalTitleMatch = bodyText.match(/原始標題\s*([^\n\r]+)/);
        if (originalTitleMatch) {
            movieInfo.originaltitle = originalTitleMatch[1].trim();
        } else {
            // 如果没找到原始标题，尝试从URL中提取英文标题
            const urlMatch = movieUrl.match(/\/movie\/\d+-(.+)$/);
            if (urlMatch) {
                movieInfo.originaltitle = urlMatch[1].replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
            } else {
                movieInfo.originaltitle = movieInfo.title;
            }
        }

        // 提取评分信息 - 从用户评分中提取
        movieInfo.rating = '0.0';

        // 提取年份和上映日期
        const yearMatch = pageTitle.match(/\((\d{4})\)/);
        if (yearMatch) {
            movieInfo.year = yearMatch[1];
        }

        // 从页面中查找上映日期
        const releaseDateText = $('body').text();
        const dateMatch = releaseDateText.match(/(\d{4}\/\d{2}\/\d{2})/);
        if (dateMatch) {
            movieInfo.premiered = dateMatch[1];
        } else if (movieInfo.year) {
            movieInfo.premiered = `${movieInfo.year}-01-01`;
        }

        // 提取运行时间
        const runtimeMatch = $('body').text().match(/(\d+)h\s*(\d+)m/);
        if (runtimeMatch) {
            const hours = parseInt(runtimeMatch[1]);
            const minutes = parseInt(runtimeMatch[2]);
            movieInfo.runtime = (hours * 60 + minutes).toString();
        } else {
            movieInfo.runtime = '120';
        }

        // 提取剧情简介
        let plot = '';

 

        // 方法2: 从 div.overview > p 中提取（推荐方法）
        if (!plot || plot.length < 5) {
            const overviewP = $('div.overview > p');
            if (overviewP.length > 0) {
                const overviewText = overviewP.text().trim();
                if (overviewText.length > 20 && !overviewText.includes('function') && !overviewText.includes('event')) {
                    plot = overviewText;
                   
                }
            }
        }
 

      

        movieInfo.plot = plot || '暂无剧情简介';
       

        // 提取标语
        let tagline = '';
        // 尝试从页面中提取标语
        const taglineMatch = bodyText.match(/### ([^#\n]+)/);
        if (taglineMatch) {
            tagline = taglineMatch[1].trim();
        }
        movieInfo.tagline = tagline;

        // 提取类型
        movieInfo.genres = [];
        const genreLinks = $('a[href*="/genre/"]');
        genreLinks.each((_, elem) => {
            const genre = $(elem).text().trim();
            if (genre && !movieInfo.genres.includes(genre)) {
                movieInfo.genres.push(genre);
            }
        });

        // 提取导演和编剧
        movieInfo.directors = [];
        movieInfo.writers = [];

        // 查找制作人员信息
        const peopleSection = $('ol li');
        peopleSection.each((_, elem) => {
            const personName = $(elem).find('a').first().text().trim();
            const jobText = $(elem).text().toLowerCase();

            if (personName) {
                if (jobText.includes('director')) {
                    movieInfo.directors.push(personName);
                } else if (jobText.includes('writer') || jobText.includes('screenplay')) {
                    movieInfo.writers.push(personName);
                }
            }
        });

        // 提取海报图片
        movieInfo.posters = [];
        const posterImages = $('img[src*="themoviedb.org"]');
        posterImages.each((_, elem) => {
            const src = $(elem).attr('src');
            if (src && src.includes('w300_and_h450') || src.includes('w220_and_h330')) {
                const fullUrl = src.replace(/\/w\d+_and_h\d+[^\/]*/, '/original');
                const previewUrl = src.replace(/\/w\d+_and_h\d+[^\/]*/, '/w500');
                movieInfo.posters.push({
                    preview: previewUrl,
                    full: fullUrl
                });
            }
        });

        // 提取背景图片
        movieInfo.fanarts = [];
        const backdropImages = $('img[src*="w533_and_h300"]');
        backdropImages.each((_, elem) => {
            const src = $(elem).attr('src');
            if (src) {
                const fullUrl = src.replace(/\/w\d+_and_h\d+[^\/]*/, '/original');
                const previewUrl = src.replace(/\/w\d+_and_h\d+[^\/]*/, '/w780');
                movieInfo.fanarts.push({
                    preview: previewUrl,
                    full: fullUrl
                });
            }
        });

        // 提取演员信息
        movieInfo.actors = [];

        // 使用正确的选择器提取演员列表
        const castList = $('#cast_scroller > ol > li');

        castList.each((i, elem) => {
            const $elem = $(elem);

            // 提取演员姓名
            let name = '';
            const $nameLinks = $elem.find('a[href*="/person/"]');

            // 尝试从不同的链接中提取姓名
            $nameLinks.each((_, link) => {
                const linkText = $(link).text().trim();
                if (linkText && !name) {
                    name = linkText;
                }
            });

            // 如果还是没有找到姓名，尝试从其他元素中提取
            if (!name) {
                const $nameElement = $elem.find('.name, h3, h4, .actor-name');
                if ($nameElement.length > 0) {
                    name = $nameElement.first().text().trim();
                }
            }

            // 提取角色名
            let role = '';
            const $character = $elem.find('.character');
            if ($character.length > 0) {
                role = $character.text().trim();
            } else {
                // 备用方法：从文本中提取角色名
                const elemText = $elem.text();
                const lines = elemText.split('\n').map(line => line.trim()).filter(line => line);
                for (let line of lines) {
                    if (line && line !== name && !line.includes('/person/') && line.length < 100) {
                        role = line;
                        break;
                    }
                }
            }

            // 提取头像
            let thumb = '';
            const $img = $elem.find('img');
            if ($img.length > 0) {
                const imgSrc = $img.attr('src');
                if (imgSrc && imgSrc.includes('w138_and_h175_face')) {
                    thumb = imgSrc.replace('/w138_and_h175_face', '/original');
                }
            }

            if (name) {
                const actor = {
                    name: name,
                    role: role,
                    order: i,
                    thumb: thumb
                };
                movieInfo.actors.push(actor);
            }
        });
        return movieInfo;
    }

    generateXML(movieInfo) {
        let xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n';
        xml += '<movie>\n';

        // 基本信息
        xml += `    <title>${this.escapeXml(movieInfo.title || '')}</title>\n`;
        xml += `    <originaltitle>${this.escapeXml(movieInfo.originaltitle || '')}</originaltitle>\n`;

        // 评分
        if (movieInfo.rating) {
            xml += '    <ratings>\n';
            xml += '        <rating name="themoviedb" max="10" default="true">\n';
            xml += `            <value>${movieInfo.rating}</value>\n`;
            xml += '            <votes>0</votes>\n';
            xml += '        </rating>\n';
            xml += '    </ratings>\n';
        }

        xml += '    <userrating>0</userrating>\n';
        xml += '    <top250>0</top250>\n';
        xml += '    <outline></outline>\n';
       
        xml += `    <plot>${this.escapeXml(movieInfo.plot || '')}</plot>\n`;
        xml += `    <tagline>${this.escapeXml(movieInfo.tagline || '')}</tagline>\n`;
        xml += `    <runtime>${movieInfo.runtime || '0'}</runtime>\n`;

        // 海报图片
        if (movieInfo.posters && movieInfo.posters.length > 0) {
            movieInfo.posters.forEach(poster => {
                xml += `    <thumb aspect="poster" preview="${poster.preview}">${poster.full}</thumb>\n`;
            });
        }

        // 背景图片
        if (movieInfo.fanarts && movieInfo.fanarts.length > 0) {
            xml += '    <fanart>\n';
            movieInfo.fanarts.forEach(fanart => {
                xml += `        <thumb preview="${fanart.preview}">${fanart.full}</thumb>\n`;
            });
            xml += '    </fanart>\n';
        }

        xml += '    <mpaa></mpaa>\n';
        xml += '    <playcount>0</playcount>\n';
        xml += '    <lastplayed></lastplayed>\n';
        xml += '    <id></id>\n';
        xml += '    <uniqueid type="imdb" default="true"></uniqueid>\n';
        xml += '    <uniqueid type="tmdb"></uniqueid>\n';

        // 类型
        if (movieInfo.genres && movieInfo.genres.length > 0) {
            movieInfo.genres.forEach(genre => {
                xml += `    <genre>${this.escapeXml(genre)}</genre>\n`;
            });
        }

        xml += '    <country></country>\n';

        // 编剧
        if (movieInfo.writers && movieInfo.writers.length > 0) {
            xml += `    <credits>${this.escapeXml(movieInfo.writers[0])}</credits>\n`;
        }

        // 导演
        if (movieInfo.directors && movieInfo.directors.length > 0) {
            xml += `    <director>${this.escapeXml(movieInfo.directors[0])}</director>\n`;
        }

        xml += `    <premiered>${movieInfo.premiered || ''}</premiered>\n`;
        xml += `    <year>${movieInfo.year || ''}</year>\n`;
        xml += '    <status></status>\n';
        xml += '    <code></code>\n';
        xml += '    <aired></aired>\n';
        xml += '    <studio></studio>\n';
        xml += '    <trailer></trailer>\n';

        // 文件信息（模板）
        xml += '    <fileinfo>\n';
        xml += '        <streamdetails>\n';
        xml += '            <video>\n';
        xml += '                <codec>h264</codec>\n';
        xml += '                <aspect>1.777778</aspect>\n';
        xml += '                <width>1920</width>\n';
        xml += '                <height>1080</height>\n';
        xml += '                <durationinseconds>0</durationinseconds>\n';
        xml += '                <stereomode></stereomode>\n';
        xml += '            </video>\n';
        xml += '            <audio>\n';
        xml += '                <codec>aac</codec>\n';
        xml += '                <language>und</language>\n';
        xml += '                <channels>2</channels>\n';
        xml += '            </audio>\n';
        xml += '        </streamdetails>\n';
        xml += '    </fileinfo>\n';

        // 演员信息
        if (movieInfo.actors && movieInfo.actors.length > 0) {
            movieInfo.actors.forEach(actor => {
                xml += '    <actor>\n';
                xml += `        <name>${this.escapeXml(actor.name)}</name>\n`;
                xml += `        <role>${this.escapeXml(actor.role)}</role>\n`;
                xml += `        <order>${actor.order}</order>\n`;
                xml += `        <thumb>${actor.thumb}</thumb>\n`;
                xml += '    </actor>\n';
            });
        }

        xml += '    <resume>\n';
        xml += '        <position>0.000000</position>\n';
        xml += '        <total>0.000000</total>\n';
        xml += '    </resume>\n';
        xml += `    <dateadded>${new Date().toISOString().replace('T', ' ').substring(0, 19)}</dateadded>\n`;
        xml += '</movie>\n';

        return xml;
    }

    escapeXml(text) {
        if (!text) return '';
        return text
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&apos;');
    }
}

// 批量处理函数
async function processBatch(moviesDir, listFile) {
    const scraper = new MovieScraper();

    try {
        // 读取电影清单
        const listContent = fs.readFileSync(listFile, 'utf8');
        const movieLines = listContent.split('\n').filter(line => line.trim());

        console.log(`找到 ${movieLines.length} 部电影待处理`);

        for (let i = 0; i < movieLines.length; i++) {
            const line = movieLines[i].trim();
            if (!line || !line.includes('||')) {
                console.log(`跳过无效行: ${line}`);
                continue;
            }

            const [movieName, movieUrl] = line.split('||');
            const movieFolderPath = path.join(moviesDir, movieName.trim());

            console.log(`\n[${i + 1}/${movieLines.length}] 处理电影: ${movieName.trim()}`);
            console.log(`电影文件夹: ${movieFolderPath}`);
            console.log(`电影URL: ${movieUrl.trim()}`);

            // 检查电影文件夹是否存在
            if (!fs.existsSync(movieFolderPath)) {
                console.log(`警告: 电影文件夹不存在，跳过: ${movieFolderPath}`);
                continue;
            }

            try {
                // 爬取电影信息到指定文件夹
                await scraper.scrapeMovieInfoToFolder(movieUrl.trim(), movieFolderPath, movieName.trim());
                console.log(`✓ 完成: ${movieName.trim()}`);

                // 添加延迟，避免请求过于频繁
                if (i < movieLines.length - 1) {
                    console.log('等待 2 秒...');
                    await new Promise(resolve => setTimeout(resolve, 2000));
                }
            } catch (error) {
                console.error(`✗ 失败: ${movieName.trim()} - ${error.message}`);
            }
        }

        console.log('\n批量处理完成！');
    } catch (error) {
        console.error('批量处理失败:', error.message);
    }
}

 

// 主函数
async function main() {
    const args = process.argv.slice(2);

    if (args.length === 0) {
        console.log('使用方法:');
        console.log('node main.js <电影文件夹路径>');
        console.log('');
        console.log('示例:');        
        console.log('node main.js "D:\\Movies"');
        return;
    }

    if (args.length === 1) {
         
        // 批量处理模式
        const moviesDir = args[0];
        const listFile = args[0] + '\\List.txt' 
        //+ args[1];

        // 验证路径
        if (!fs.existsSync(moviesDir)) {
            console.error(`错误: 电影文件夹不存在: ${moviesDir}`);
            return;
        }

        if (!fs.existsSync(listFile)) {
            console.error(`错误: 清单文件不存在: ${listFile}`);
            return;
        }

        await processBatch(moviesDir, listFile);
    } else {
        console.error('错误: 参数数量不正确');
        console.log('使用 node main.js 查看使用方法');
    }
}

// 如果直接运行此文件，则执行主函数
if (require.main === module) {
    main();
}

module.exports = MovieScraper;